using System;
using System.Collections.Generic;
using System.Text;
using Rapier.Kodachi.Shared;
using System.Drawing;
using System.Runtime.InteropServices;

namespace Rapier.Kodachi.SystemCommands.Actions
{
    public class ShutDown : Action
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
            [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
            ref TOKEN_PRIVILEGES NewState,
            UInt32 BufferLength,
            IntPtr PreviousState,
            IntPtr ReturnLength);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool OpenProcessToken(IntPtr ProcessHandle,
            UInt32 DesiredAccess, out IntPtr TokenHandle);

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern bool LookupPrivilegeValue(string lpSystemName, string lpName,
            out LUID lpLuid);

        [DllImport("user32.dll")]
        public static extern int ExitWindowsEx(int uFlags, int dwReason);

       private Bitmap shutdownImage; 

        #region Constructor
        public ShutDown(Plugin plugin)
            : base(plugin, "Rapier.Kodachi.SystemCommands.ShutDown", "Shut Down Windows", "Close all apps and shut down windows.")
        {
            AdjustShutdownTokenPriveleges();
            shutdownImage = Rapier.Kodachi.SystemCommands.Properties.Resources.Shutdown.ToBitmap();
            this.IndirectItemUse = IndirectItemUse.None;
            GetImage = delegate()
            {
               return shutdownImage;
            };
        }
        #endregion

        #region Action Members
        public override void Execute(Item[] directItems, Item[] indirectItems)
        {
            ExitWindowsEx(1, 0);
        }

        public override bool IsValidIndirect(Item indirectItem)
        {
            return false;
        }

        public override bool IsValidDirect(Item directItem)
        {
            return directItem.Properties.ContainsKey("SystemCommand") && (bool)(directItem.Properties["SystemCommand"]) == true;
        }
        #endregion

        static private bool AdjustShutdownTokenPriveleges()
        {
            bool ret;

            IntPtr hProc = IntPtr.Zero;
            IntPtr hToken = IntPtr.Zero;
            LUID luidRestore;
            TOKEN_PRIVILEGES tokenPriviliges;

            // get the current current process security token
            hProc = System.Diagnostics.Process.GetCurrentProcess().Handle;
            ret = OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
            if (!ret)
                return false;


            // lookup the LUID for the shutdown privilege
            ret = LookupPrivilegeValue(String.Empty, SE_SHUTDOWN_NAME, out luidRestore);
            if (!ret)
                return false;

            // adjust the privileges of the current process to include the shutdown privilege
            tokenPriviliges.PrivilegeCount = 1;
            tokenPriviliges.Luid = luidRestore;
            tokenPriviliges.Attributes = SE_PRIVILEGE_ENABLED;

            TOKEN_PRIVILEGES tokenTemp = new TOKEN_PRIVILEGES();

            ret = AdjustTokenPrivileges(hToken, false, ref tokenPriviliges, 0, IntPtr.Zero, IntPtr.Zero);
            if (!ret)
                return false;

            return true;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct TOKEN_PRIVILEGES
        {
            public int PrivilegeCount;
            public LUID Luid;
            public int Attributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct LUID
        {
            public uint LowPart;
            public uint HighPart;
        }

        private const int TOKEN_QUERY = 0x08;
        private const int TOKEN_ADJUST_PRIVILEGES = 0x20;
        private const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
        private const int SE_PRIVILEGE_ENABLED = 0x02;

    }
}
